package com.yuchen.ishop.goods;

import com.alibaba.dubbo.rpc.protocol.rest.support.ContentType;
import com.yuchen.core.MyPager;
import com.yuchen.core.jdbc.BaseDao;
import com.yuchen.ishop.MyPagerUtils;
import com.yuchen.ishop.entity.Goods;
import com.yuchen.ishop.entity.GoodsContent;
import com.yuchen.ishop.entity.GoodsHouse;
import com.yuchen.ishop.entity.GoodsImg;
import com.yuchen.jaxrs.ResponseUtils;
import com.yuchen.jaxrs.Responses;
import com.yuchen.utils.fastjson.JsonUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.time.DurationFormatUtils;
import org.apache.log4j.Logger;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Condition;
import org.nutz.service.EntityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 */
@Transactional
@Path("goodsService")
@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
public class GoodsServiceImpl implements GoodsService {

    private final static Logger LOG = Logger.getLogger(GoodsService.class);

    private final static String[] orderby = {"asc", "desc"};

    @Autowired
    private BaseDao dao;

    @POST
    @Path("find")
    @Transactional(readOnly = true)
    public MyPager find(Map params) {
        MyPager myPager = MyPagerUtils.myPager(params);
        String sql = buildSql(params);
        return dao.queryPager(sql.toString(), params, myPager);
    }

    @POST
    @Path("findByLimit")
    @Transactional(readOnly = true)
    public MyPager findByLimit(Map params) {
        int pageSize = 5;
        if (params != null && params.size() > 0) {
            if (params.get("pageSize") != null) {
                pageSize = NumberUtils.toInt(params.get("pageSize").toString());
            }
        }
        String sql = buildSql(params);
        return dao.queryLimitPager(sql.toString(), params, pageSize);
    }

    @GET
    @Path("get/{id}")
    @Transactional(readOnly = true)
    public Goods get(@PathParam("id") Long id) {
        Goods goods = dao.fetch(Goods.class, id);
        GoodsContent content = dao.fetch(GoodsContent.class, Cnd.where("goodsId", "=", goods.getId()));
        if (content != null) {
            goods.setContent(content.getContent());
        }
        GoodsHouse house = dao.fetch(GoodsHouse.class, Cnd.where("goodsId", "=", goods.getId()));
        if (house != null) {
            goods.setHouse(house);
        }
        return goods;
    }

    @GET
    @Path("existGoods/{userId}/{id}/{role}")
    @Transactional(readOnly = true)
    public Responses existGoods(@PathParam("userId") Long userId, @PathParam("id") Long id, @PathParam("role") String role) {
        Cnd c = Cnd.where("id", "=", id);
        if ("seller".equals(role)) {
            c.and("sellerId", "=", userId);
        }
        if ("buyer".equals(role)) {
            c.and("buyerId", "=", userId);
        }
        if ("xiaoer".equals(role)) {
            c.and("xiaoerId", "=", userId);
        }
        Goods goods = dao.fetch(Goods.class, c);
        return goods != null ? ResponseUtils.success() : ResponseUtils.error();
    }

    @GET
    @Path("isAccessGoods/{id}")
    @Transactional(readOnly = true)
    public Boolean isAccessGoods(@PathParam("id") Long id) {
        Goods goods = dao.fetch(Goods.class, id);
        if (goods != null && goods.getPublishState() == 1) {
            return true;
        }
        return false;
    }


    @POST
    @Path("insert")
    public Responses insert(Goods goods) {
        /*if(goods.getState()==null){
            goods.setState(1l);
        }*/
        goods = dao.insert(goods);
        if (StringUtils.isNotBlank(goods.getContent())) {
            GoodsContent goodsContent = new GoodsContent();
            goodsContent.setContent(goods.getContent());
            goodsContent.setGoodsId(goods.getId());
            dao.insert(goodsContent);
        }
        if (StringUtils.isNotBlank(goods.getImgIds())) {
            updateGoodsImg(goods.getImgIds(), goods.getId());
        }
        GoodsHouse house = goods.getHouse();
        if (house != null) {
            house.setHouseFloor(house.getHouseFloor1() + "/" + house.getHouseFloor2());
            house.setGoodsId(goods.getId());
            house.setCreateTime(goods.getCreateTime());
            dao.insert(house);
        }
        Responses responses = ResponseUtils.success();
        //responses.setJson(JsonUtils.toJSON(goods));
        return responses;
    }


    @DELETE
    @Path("delete/{id}")
    public Responses delete(@PathParam("id") Long id) {
        dao.delete(GoodsContent.class, id);
        dao.delete(GoodsHouse.class, id);
        dao.delete(Goods.class, id);
        return ResponseUtils.success();
    }

    @POST
    @Path("update")
    public Responses update(Goods goods) {
        dao.updateIgnoreNull(goods);
        if (StringUtils.isNotBlank(goods.getContent())) {
            GoodsContent goodsContent = dao.fetch(GoodsContent.class, goods.getId());
            if (goodsContent == null) {
                goodsContent = new GoodsContent();
                goodsContent.setGoodsId(goods.getId());
                goodsContent.setContent(goods.getContent());
                dao.insert(goodsContent);
            } else {
                dao.update(GoodsContent.class, Chain.make("content", goods.getContent()), Cnd.where("goodsId", "=", goods.getId()));
            }
        }
        if (StringUtils.isNotBlank(goods.getImgIds())) {
            updateGoodsImg(goods.getImgIds(), goods.getId());
        } else {//
            Condition cnd = Cnd.where("goodsId", "=", goods.getId()).and("type", "=", 1);
            int count = dao.count(GoodsImg.class, cnd);
            if (count <= 0) {
                GoodsImg goodsImg = dao.fetch(GoodsImg.class, Cnd.where("goodsId", "=", goods.getId()));
                goodsImg.setType(1l);
                dao.updateIgnoreNull(goodsImg);
            }
        }
        GoodsHouse house = goods.getHouse();
        if (house != null) {
            house.setHouseFloor(house.getHouseFloor1() + "/" + house.getHouseFloor2());
            house.setGoodsId(goods.getId());
            dao.updateIgnoreNull(house);
        }
        return ResponseUtils.success();
    }


    @POST
    @Path("lockGoods")
    public Responses lockGoods(Long id) {
        dao.update(Goods.class, Chain.make("state", 2), Cnd.where("id", "=", id));
        return ResponseUtils.success();
    }

    @POST
    @Path("offGoods")
    public Responses offGoods(Long id) {
        Chain chain = Chain.make("publishState", 0);
        chain.add("updateTime", new Timestamp(System.currentTimeMillis()));
        dao.update(Goods.class, chain, Cnd.where("id", "=", id));
        return ResponseUtils.success();
    }

    @POST
    @Path("upGoods")
    public Responses upGoods(Long id) {
        Chain chain = Chain.make("publishState", 1);
        chain.add("updateTime", new Timestamp(System.currentTimeMillis()));
        dao.update(Goods.class, chain, Cnd.where("id", "=", id));
        return ResponseUtils.success();
    }

    @POST
    @Path("refresh")
    public Responses refresh(Long id) {
        Goods goods = dao.fetch(Goods.class, id);
        if (goods != null) {
            Timestamp currentTime = new Timestamp(System.currentTimeMillis());
            Long refresh = goods.getRefresh()==null?0l:goods.getRefresh();
            Timestamp refreshTime = goods.getRefreshTime();
            if(refreshTime==null){
                Chain chain = Chain.make("refreshTime", currentTime);
                chain.add("refresh", refresh+1);
                dao.update(Goods.class, chain, Cnd.where("id", "=", id));
                return ResponseUtils.success();
            }else{
               String durationByMinute  = DurationFormatUtils.formatPeriod(
                        refreshTime.getTime(), currentTime.getTime(), "m");
                if(Long.valueOf(durationByMinute)>60){
                    Chain chain = Chain.make("refreshTime", currentTime);
                    chain.add("refresh", refresh+1);
                    dao.update(Goods.class, chain, Cnd.where("id", "=", id));
                    return ResponseUtils.success();
                }else{
                  return  ResponseUtils.error("间隔1个小时才能在刷新！");
                }
            }
        }
        return ResponseUtils.error();
    }

    private String buildSql(Map params) {
        Map min_max = null;
        StringBuilder sql = new StringBuilder();
        sql.append("select ");
        sql.append("g.id as id ,g.name as name ,g.create_time as createtime,g.price as price,g.seller_id as seller_id,g.seller_xiaoer_id as xiaoer_id, ");
        sql.append("g.state as state,g.room as room ,g.hall as hall ,g.toilet as toilet,g.house_size as housesize,g.sys_type_name as sys_type_name, ");
        sql.append("g.orientation as orientation ,g.house_floor as housefloor ,g.house_age as houseage,g.structure as structure, ");
        sql.append("g.decorate as decorate,g.subway as subway ,g.province_id as province_id ,g.city_id as city_id,g.area_id as area_id,g.owner as owner,g.owner_phone as owner_phone, ");
        sql.append("g.community_name as community_name,g.refresh,g.refresh_time ");
        sql.append("from goods_views g ");
        sql.append("where 1=1 ");
        if (params != null && params.size() > 0) {
            if (params.get("id") != null) {
                sql.append("and g.id =@id ");
            }
            if (params.get("ids") != null) {
                sql.append("and g.id in (" + params.get("ids") + ") ");
            }
            if (params.get("sellerId") != null) {
                sql.append("and g.seller_id =@sellerId ");
            }
            if (params.get("xiaoerId") != null) {
                sql.append("and g.seller_xiaoer_id =@xiaoerId ");
            }
            if (params.get("dictionaryId") != null) {
                sql.append("and g.dictionary_id =@dictionaryId ");
            }
            if (params.get("recommend") != null) {
                sql.append("and g.recommend =@recommend ");
            }
            if (params.get("publicState") != null) {
                sql.append("and g.public_state =@publicState ");
            } else {
                sql.append("and g.public_state =1 ");
            }
            //导购查询 TODO: lucene
            if (isNotBlank(params.get("area_id"))) {
                sql.append("and g.area_id =@area_id ");
            }
            if (isNotBlank(params.get("price"))) {
                min_max = between(params.get("price"), "-");
                if (isNotBlank(min_max.get("min"))) {
                    params.put("priceMin", min_max.get("min"));
                    sql.append("and g.price >=@priceMin ");
                }
                if (isNotBlank(min_max.get("max"))) {
                    params.put("priceMax", min_max.get("max"));
                    sql.append("and g.price <=@priceMax ");
                }
            }
            if (isNotBlank(params.get("house_size"))) {
                min_max = between(params.get("house_size"), "-");
                if (isNotBlank(min_max.get("min"))) {
                    params.put("houseSizeMin", min_max.get("min"));
                    sql.append("and g.house_size >=@houseSizeMin ");
                }
                if (isNotBlank(min_max.get("max"))) {
                    params.put("houseSizeMax", min_max.get("max"));
                    sql.append("and g.house_size <=@houseSizeMax ");
                }
            }
            if (isNotBlank(params.get("room"))) {
                min_max = between(params.get("room"), "-");
                if (isNotBlank(min_max.get("min"))) {
                    params.put("roomMin", min_max.get("min"));
                    sql.append("and g.room >@roomMin ");
                }
                if (isNotBlank(min_max.get("max"))) {
                    params.put("roomMax", min_max.get("max"));
                    sql.append("and g.room <=@roomMax ");
                }
            }

            //keywords
            if (isNotBlank(params.get("keywords"))) {
                sql.append(" and (g.name like concat('%',@lName, '%')  or g.content like  concat('%',@lContent, '%') ) ");
                params.put("lName", params.get("keywords"));
                params.put("lContent", params.get("keywords"));
            }

        }


        //order by
        if (isNotBlank(params.get("orderbyPrice"))) {
            if (ArrayUtils.contains(orderby, params.get("orderbyPrice"))) {
                sql.append("order by g.price ").append(params.get("orderbyPrice"));
            }
        }
        if (isNotBlank(params.get("orderbySize"))) {
            if (ArrayUtils.contains(orderby, params.get("orderbySize"))) {
                sql.append("order by g.house_size ").append(params.get("orderbySize"));
            }
        }
        if (!isNotBlank(params.get("orderbyPrice")) && !isNotBlank(params.get("orderbySize"))) {
            sql.append("order by g.refresh desc");
        }
        return sql.toString();
    }

    private void updateGoodsImg(String ids, Long goodsId) {
        String[] imgs = ids.split(",");
        dao.update(GoodsImg.class, Chain.make("goodsId", goodsId), Cnd.where("id", "in", imgs));
        Condition cnd = Cnd.where("id", "in", imgs).and("type", "=", 1);
        GoodsImg mainImg = dao.fetch(GoodsImg.class, cnd);
        if (mainImg == null) {
            dao.update(GoodsImg.class, Chain.make("type", 1), Cnd.where("id", "=", imgs[0]));
        }
    }

    private boolean isNotBlank(Object val) {
        if (val == null) return false;
        return StringUtils.isNotBlank(val.toString());
    }

    private Map<String, Object> between(Object val, String pattern) {
        String[] s = val.toString().split(pattern);
        if (s != null && s.length == 1) {
            Map<String, Object> map = new HashMap<String, Object>(1);
            map.put("min", s[0]);
            return map;
        } else if (s.length == 2) {
            Map<String, Object> map = new HashMap<String, Object>(2);
            map.put("min", s[0]);
            map.put("max", s[1]);
            return map;
        }
        return null;
    }
}
